namespace designpatternsplusplus.decorator.DomainEntities
{
    #region

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.Text;
    using designpatternsplus.contracts;

    #endregion

    /// <summary>
    /// Our internal serialized record of the sale
    /// 
    /// Single Responsibility: A receipt we both use internally
    /// in a serialized formatted audit trail as well as 
    /// a transform to a style we can give to the customer
    /// They are simply projections/transforms from this immutable
    /// item (nothing can change here after it is created)
    /// Modifications must be new Transaction Record which
    /// are 'adjusting entries' in accounting terms
    /// </summary>
    [Serializable]
    public sealed class SalesReceipt : ShoppingCart, ISalesReceipt
    {
        readonly DateTime _transactionDateTime;
        double _totalSale;
        double _totalTax;

        /// <summary>
        /// Initializes a new instance of the <see cref="SalesReceipt"/> class.
        /// </summary>
        internal SalesReceipt()
        {
            
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="SalesReceipt"/> class.
        /// </summary>
        /// <param name="ItemsSold">The items sold.</param>
        public SalesReceipt(IEnumerable<IProductService> ItemsSold) : base(ItemsSold)
        {
            _transactionDateTime = DateTime.Now;
            TransactionId = Guid.NewGuid().ToString();
            SetTotals(ItemsSold);
        }

        /// <summary>
        /// Gets the <see cref="IProductService"/> with the specified sku.
        /// </summary>
        /// <value></value>
        public IProductService this[String sku]
        {
            get
            {
                return
                    this.Where(sellableItemIn => sellableItemIn.Sku == sku).FirstOrDefault
                        ();
            }
        }

        /// <summary>
        /// Gets or sets the total sale.
        /// </summary>
        /// <value>The total sale.</value>
        public double TotalSale
        {
            get { return Math.Round(_totalSale, 2); }
            private set { _totalSale = value; }
        }

        /// <summary>
        /// Gets the transaction date time.
        /// We setthis in the ctor
        /// </summary>
        /// <value>The transaction date time.</value>
        public DateTime TransactionDateTime
        {
            get { return _transactionDateTime; }
        }

        /// <summary>
        /// Gets or sets the total tax for the receipt
        /// </summary>
        /// <value>The total tax.</value>
        public double TotalTax
        {
            get { return Math.Round(_totalTax, 2); }
            private set { _totalTax = value; }
        }

        /// <summary>
        /// Gets or sets the transaction id
        /// for the receipt which is unique for all
        /// </summary>
        /// <value>The transaction id.</value>
        public string TransactionId { get; private set; }

        /// <summary>
        /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
        /// </returns>
        public override string ToString()
        {
            var sb = new StringBuilder();

            sb.AppendLine("* RECEIPT FOR TRANSACTION " + TransactionId);
            foreach (var item in this)
                sb.AppendLine(item.ToString());

            sb.AppendLine(new string('=', 20));

            sb.AppendLine(TotalTax.ToString("C") + " Tax");
            sb.AppendLine(TotalSale.ToString("C") + " Sale");

            return sb.ToString();
        }

        /// <summary>
        /// Sets the totals for tax, sale, etc.
        /// </summary>
        /// <param name="current">The current.</param>
        void SetTotals(IEnumerable<IProductService> current)
        {
            TotalSale = 0;
            TotalTax = 0;
            foreach (var _value in current)
                UpdateTotalFromItem(_value);
        }

        void UpdateTotalFromItem(IProductService _value)
        {
            var _amount = _value.Amount();
            _totalSale += _amount;
            _totalTax += _amount - _value.BaseAmount;
        }
    }
}